import fs from 'fs'
import path from 'path'
import { Send } from '@/send'
import { globalLogger } from '@/log'
import { validHost } from '@/utils/validate'
import { getErrorMessage } from '@/utils/error'
import { readConfigFileWithSend } from '@/configFile'
import type { Command } from 'commander'
import type { CommandModule } from '@/types/cli'
import type { ParsedSendConfig } from '@/types/configFile'
import config from '@/config'
import ignore from 'ignore'

const command: CommandModule = {
  name: 'send',
  args: ['<name>'],
  description: 'send files',
  options: [
    { flags: '--param', description: 'param mode' },
    { flags: '--path <path>' },
    { flags: '--host <host>' },
    { flags: '--port <port>' }
  ],
  action(args: [string, Options, Command], opts) {
    const name = args[0]
    const options = args[1]

    try {
      if (options.param) {
        const config = parseParamMode(name, options)
        new Send(config, config.project[0], 'param')
      } else {
        const config = readConfigFileWithSend(opts.config)
        const currentConfig = config.project.find((project) => project.name === name)
        if (!currentConfig) {
          throw new Error(`project ${name} not found`)
        }
        new Send(config, currentConfig)
      }
    } catch (error) {
      const err = getErrorMessage(error)
      globalLogger.send.error(err)
      console.error(err)
    }
  }
}

function parseParamMode(name: string, options: Options): ParsedSendConfig {
  if (!options.path) throw new Error('path is required')
  const fullPath = path.join(process.cwd(), options.path)
  if (!fs.existsSync(fullPath)) throw new Error('path not found')
  if (!fs.statSync(fullPath).isDirectory()) throw new Error('path is not a directory')

  if (!options.host) throw new Error('host is required')
  const host = options.host.trim()
  if (!validHost(host)) throw new Error('invalid host')

  let port = config.default.port
  if (options.port) {
    port = parseInt(options.port)
    if (isNaN(port)) throw new Error('port is not a number')
    if (port < 1 || port > 65535) throw new Error('port is out of range')
  }

  return {
    project: [
      {
        name,
        path: fullPath,
        host,
        port,
        ignore: ignore().add(config.default.sendIgnore)
      }
    ]
  }
}

type Options = {
  param?: true
  path?: string
  host?: string
  port?: string
}

export default command
